home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / ada_gnu / adainc / a-strfix.adb < prev    next >
Text File  |  1996-01-30  |  16KB  |  609 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT RUNTIME COMPONENTS                          --
  4. --                                                                          --
  5. --                    A D A . S T R I N G S . F I X E D                     --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.7 $                              --
  10. --                                                                          --
  11. --           Copyright (c) 1992,1993,1994 NYU, All Rights Reserved          --
  12. --                                                                          --
  13. -- The GNAT library is free software; you can redistribute it and/or modify --
  14. -- it under terms of the GNU Library General Public License as published by --
  15. -- the Free Software  Foundation; either version 2, or (at your option) any --
  16. -- later version.  The GNAT library is distributed in the hope that it will --
  17. -- be useful, but WITHOUT ANY WARRANTY;  without even  the implied warranty --
  18. -- of MERCHANTABILITY  or  FITNESS FOR  A PARTICULAR PURPOSE.  See the  GNU --
  19. -- Library  General  Public  License for  more  details.  You  should  have --
  20. -- received  a copy of the GNU  Library  General Public License  along with --
  21. -- the GNAT library;  see the file  COPYING.LIB.  If not, write to the Free --
  22. -- Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.        --
  23. --                                                                          --
  24. ------------------------------------------------------------------------------
  25.  
  26. --  Note: This code is derived from the ADAR.CSH public domain Ada 83
  27. --  versions of the Appendix C string handling packages. One change is
  28. --  to avoid the use of Is_In, so that we are not dependent on inlining.
  29. --  Note that the search function implementations are to be found in the
  30. --  auxiliary package Ada.Strings.Search. Also the Move procedure is
  31. --  directly incorporated (ADAR used a subunit for this procedure)
  32.  
  33. with Ada.Strings.Maps; use Ada.Strings.Maps;
  34.  
  35. package body Ada.Strings.Fixed is
  36.  
  37.    ---------
  38.    -- "*" --
  39.    ---------
  40.  
  41.    function "*"
  42.      (Left  : in Natural;
  43.       Right : in Character)
  44.       return  String
  45.    is
  46.       Result : String (1 .. Left);
  47.  
  48.    begin
  49.       for J in Result'Range loop
  50.          Result (J) := Right;
  51.       end loop;
  52.  
  53.       return Result;
  54.    end "*";
  55.  
  56.    function "*"
  57.      (Left  : in Natural;
  58.       Right : in String)
  59.       return  String
  60.    is
  61.       Result : String (1 .. Left * Right'Length);
  62.       Ptr    : Integer := 1;
  63.  
  64.    begin
  65.       for J in 1 .. Left loop
  66.          Result (Ptr .. Ptr + Right'Length - 1) := Right;
  67.          Ptr := Ptr + Right'Length;
  68.       end loop;
  69.  
  70.       return Result;
  71.    end "*";
  72.  
  73.    ------------
  74.    -- Delete --
  75.    ------------
  76.  
  77.    function Delete
  78.      (Source  : in String;
  79.       From    : in Positive;
  80.       Through : in Natural)
  81.       return    String
  82.    is
  83.       Result : String
  84.                  (1 .. Source'Length - Integer'Max (Through - From + 1, 0));
  85.  
  86.    begin
  87.       if From not in Source'Range or else Through > Source'Last then
  88.          raise Index_Error;
  89.       end if;
  90.  
  91.       Result := Source (Source'First .. From - 1) &
  92.                 Source (Through + 1 .. Source'Last);
  93.       return Result;
  94.    end Delete;
  95.  
  96.    procedure Delete
  97.      (Source  : in out String;
  98.       From    : in Positive;
  99.       Through : in Natural;
  100.       Justify : in Alignment := Left;
  101.       Pad     : in Character := Space)
  102.    is
  103.    begin
  104.       Move (Source  => Delete (Source, From, Through),
  105.             Target  => Source,
  106.             Justify => Justify,
  107.             Pad     => Pad);
  108.    end Delete;
  109.  
  110.    ----------
  111.    -- Head --
  112.    ----------
  113.  
  114.    function Head
  115.      (Source : in String;
  116.       Count  : in Natural;
  117.       Pad    : in Character := Space)
  118.       return   String
  119.    is
  120.       Result : String (1 .. Count);
  121.  
  122.    begin
  123.       if Count < Source'Length then
  124.          Result := Source (Source'First .. Source'First + Count - 1);
  125.  
  126.       else
  127.          Result (1 .. Source'Length) := Source;
  128.  
  129.          for J in Source'Length + 1 .. Count loop
  130.             Result (J) := Pad;
  131.          end loop;
  132.       end if;
  133.  
  134.       return Result;
  135.    end Head;
  136.  
  137.    procedure Head
  138.      (Source  : in out String;
  139.       Count   : in Natural;
  140.       Justify : in Alignment := Left;
  141.       Pad     : in Character := Space)
  142.    is
  143.    begin
  144.       if Count < Source'Length then
  145.          Source := Source (Source'First .. Source'First + Count - 1);
  146.       else
  147.          for J in Source'Length + 1 .. Count loop
  148.             Source (J) := Pad;
  149.          end loop;
  150.       end if;
  151.  
  152.    end Head;
  153.  
  154.    ------------
  155.    -- Insert --
  156.    ------------
  157.  
  158.    function Insert
  159.      (Source   : in String;
  160.       Before   : in Positive;
  161.       New_Item : in String)
  162.       return     String
  163.    is
  164.       Result : String (1 .. Source'Length + New_Item'Length);
  165.  
  166.    begin
  167.       if Before < Source'First or else Before > Source'Last + 1 then
  168.          raise Index_Error;
  169.       end if;
  170.  
  171.       Result := Source (Source'First .. Before - 1) & New_Item &
  172.                 Source (Before .. Source'Last);
  173.       return Result;
  174.    end Insert;
  175.  
  176.    procedure Insert
  177.      (Source   : in out String;
  178.       Before   : in Positive;
  179.       New_Item : in String;
  180.       Drop     : in Truncation := Error)
  181.    is
  182.    begin
  183.       Move (Source => Insert (Source, Before, New_Item),
  184.             Target => Source,
  185.             Drop   => Drop);
  186.    end Insert;
  187.  
  188.    ----------
  189.    -- Move --
  190.    ----------
  191.  
  192.    procedure Move
  193.      (Source  : in  String;
  194.       Target  : out String;
  195.       Drop    : in  Truncation := Error;
  196.       Justify : in  Alignment  := Left;
  197.       Pad     : in  Character  := Space)
  198.    is
  199.       Sfirst  : constant Integer := Source'First;
  200.       Slast   : constant Integer := Source'Last;
  201.       Slength : constant Integer := Source'Length;
  202.  
  203.       Tfirst  : constant Integer := Target'First;
  204.       Tlast   : constant Integer := Target'Last;
  205.       Tlength : constant Integer := Target'Length;
  206.  
  207.       function Is_Padding (Item : String) return Boolean;
  208.       --  Check if Item is all Pad characters, return True if so, False if not
  209.  
  210.       function Is_Padding (Item : String) return Boolean is
  211.       begin
  212.          for J in Item'Range loop
  213.             if Item (J) /= Pad then
  214.                return False;
  215.             end if;
  216.          end loop;
  217.  
  218.          return True;
  219.       end Is_Padding;
  220.  
  221.    --  Start of processing for Move
  222.  
  223.    begin
  224.       if Slength = Tlength then
  225.          Target := Source;
  226.  
  227.       elsif Slength > Tlength then
  228.  
  229.          case Drop is
  230.             when Left =>
  231.                Target := Source (Slast - Tlength + 1 .. Slast);
  232.  
  233.             when Right =>
  234.                Target := Source (Sfirst .. Sfirst + Tlength - 1);
  235.  
  236.             when Error =>
  237.                case Justify is
  238.                   when Left =>
  239.                      if Is_Padding (Source (Sfirst + Tlength .. Slast)) then
  240.                         Target :=
  241.                           Source (Sfirst .. Sfirst + Target'Length - 1);
  242.                      else
  243.                         raise Length_Error;
  244.                      end if;
  245.  
  246.                   when Right =>
  247.                      if Is_Padding (Source (Sfirst .. Slast - Tlength)) then
  248.                         Target := Source (Slast - Tlength + 1 .. Slast);
  249.                      else
  250.                         raise Length_Error;
  251.                      end if;
  252.  
  253.                   when Center =>
  254.                      raise Length_Error;
  255.                end case;
  256.  
  257.          end case;
  258.  
  259.       else -- Source'Length < Target'Length
  260.  
  261.          case Justify is
  262.             when Left =>
  263.                Target (Tfirst .. Tfirst + Slength - 1) := Source;
  264.  
  265.                for I in Tfirst + Slength .. Tlast loop
  266.                   Target (I) := Pad;
  267.                end loop;
  268.  
  269.             when Right =>
  270.                for I in Tfirst .. Tlast - Slength loop
  271.                   Target (I) := Pad;
  272.                end loop;
  273.  
  274.                Target (Tlast - Slength + 1 .. Tlast) := Source;
  275.  
  276.             when Center =>
  277.                declare
  278.                   Front_Pad   : constant Integer := (Tlength - Slength) / 2;
  279.                   Tfirst_Fpad : constant Integer := Tfirst + Front_Pad;
  280.  
  281.                begin
  282.                   for I in Tfirst .. Tfirst_Fpad - 1 loop
  283.                      Target (I) := Pad;
  284.                   end loop;
  285.  
  286.                   Target (Tfirst_Fpad .. Tfirst_Fpad + Slength - 1) := Source;
  287.  
  288.                   for I in Tfirst_Fpad + Slength .. Tlast loop
  289.                      Target (I) := Pad;
  290.                   end loop;
  291.                end;
  292.          end case;
  293.       end if;
  294.    end Move;
  295.  
  296.    ---------------
  297.    -- Overwrite --
  298.    ---------------
  299.  
  300.    function Overwrite
  301.      (Source   : in String;
  302.       Position : in Positive;
  303.       New_Item : in String)
  304.       return     String
  305.    is
  306.    begin
  307.       if Position not in Source'First .. Source'Last + 1 then
  308.          raise Index_Error;
  309.       end if;
  310.  
  311.       declare
  312.          Result_Length : Natural :=
  313.            Integer'Max
  314.              (Source'Length, Position - Source'First + New_Item'Length);
  315.  
  316.          Result : String (1 .. Result_Length);
  317.  
  318.       begin
  319.          Result := Source (Source'First .. Position - 1) & New_Item &
  320.                    Source (Position + New_Item'Length .. Source'Last);
  321.          return Result;
  322.       end;
  323.    end Overwrite;
  324.  
  325.    procedure Overwrite
  326.      (Source   : in out String;
  327.       Position : in Positive;
  328.       New_Item : in String;
  329.       Drop     : in Truncation := Right)
  330.    is
  331.    begin
  332.       Move (Source => Overwrite (Source, Position, New_Item),
  333.             Target => Source,
  334.             Drop   => Drop);
  335.    end Overwrite;
  336.  
  337.    -------------------
  338.    -- Replace_Slice --
  339.    -------------------
  340.  
  341.    function Replace_Slice
  342.      (Source   : in String;
  343.       Low      : in Positive;
  344.       High     : in Natural;
  345.       By       : in String)
  346.       return     String
  347.    is
  348.       Result_Length : Natural;
  349.  
  350.    begin
  351.       if Low > Source'Last + 1 or High < Source'First - 1 then
  352.          raise Index_Error;
  353.       end if;
  354.  
  355.       Result_Length :=
  356.         Source'Length - Integer'Max (High - Low + 1, 0) + By'Length;
  357.  
  358.       declare
  359.          Result : String (1 .. Result_Length);
  360.  
  361.       begin
  362.          if High >= Low then
  363.             Result :=
  364.                Source (Source'First .. Low - 1) & By &
  365.                Source (High + 1 .. Source'Last);
  366.          else
  367.             Result := Source (Source'First .. Low - 1) & By &
  368.                       Source (Low .. Source'Last);
  369.          end if;
  370.          return Result;
  371.       end;
  372.    end Replace_Slice;
  373.  
  374.    procedure Replace_Slice
  375.      (Source   : in out String;
  376.       Low      : in Positive;
  377.       High     : in Natural;
  378.       By       : in String;
  379.       Drop     : in Truncation := Error;
  380.       Justify  : in Alignment  := Left;
  381.       Pad      : in Character  := Space)
  382.    is
  383.    begin
  384.       Move (Replace_Slice (Source, Low, High, By), Source, Drop, Justify, Pad);
  385.    end Replace_Slice;
  386.  
  387.    ----------
  388.    -- Tail --
  389.    ----------
  390.  
  391.    function Tail
  392.      (Source : in String;
  393.       Count  : in Natural;
  394.       Pad    : in Character := Space)
  395.       return   String
  396.    is
  397.       Result : String (1 .. Count);
  398.  
  399.    begin
  400.       if Count < Source'Length then
  401.          Result := Source (Source'Last - Count + 1 .. Source'Last);
  402.  
  403.       --  Pad on left
  404.  
  405.       else
  406.          for J in 1 .. Count - Source'Length loop
  407.             Result (J) := Pad;
  408.          end loop;
  409.  
  410.          Result (Count - Source'Length + 1 .. Count) := Source;
  411.       end if;
  412.  
  413.       return Result;
  414.    end Tail;
  415.  
  416.    procedure Tail
  417.      (Source  : in out String;
  418.       Count   : in Natural;
  419.       Justify : in Alignment := Left;
  420.       Pad     : in Character := Space)
  421.    is
  422.       Temp : String (1 .. Source'Length);
  423.  
  424.    begin
  425.       --  raise Program_Error;
  426.       Temp (1 .. Source'Length) := Source;
  427.       if Count < Source'Length then
  428.          Source := Temp (Temp'Last - Count + 1 .. Temp'Last);
  429.  
  430.       --  Pad on left
  431.  
  432.       else
  433.          for J in 1 .. Count - Temp'Length loop
  434.             Source (J) := Pad;
  435.          end loop;
  436.  
  437.          Source (Count - Temp'Length + 1 .. Count) := Temp;
  438.       end if;
  439.  
  440.    end Tail;
  441.  
  442.    ---------------
  443.    -- Translate --
  444.    ---------------
  445.  
  446.    function Translate
  447.      (Source  : in String;
  448.       Mapping : in Maps.Character_Mapping)
  449.       return    String
  450.    is
  451.       Result : String (1 .. Source'Length);
  452.  
  453.    begin
  454.       for J in Source'Range loop
  455.          Result (J - (Source'First - 1)) := Value (Mapping, Source (J));
  456.       end loop;
  457.  
  458.       return Result;
  459.    end Translate;
  460.  
  461.    procedure Translate
  462.      (Source  : in out String;
  463.       Mapping : in Maps.Character_Mapping)
  464.    is
  465.    begin
  466.       for J in Source'Range loop
  467.          Source (J) := Value (Mapping, Source (J));
  468.       end loop;
  469.    end Translate;
  470.  
  471.    function Translate
  472.      (Source  : in String;
  473.       Mapping : in Maps.Character_Mapping_Function)
  474.       return    String
  475.    is
  476.       Result : String (1 .. Source'Length);
  477.  
  478.    begin
  479.       for J in Source'Range loop
  480.          Result (J - (Source'First - 1)) := Mapping.all (Source (J));
  481.       end loop;
  482.  
  483.       return Result;
  484.    end Translate;
  485.  
  486.    procedure Translate
  487.      (Source  : in out String;
  488.       Mapping : in Maps.Character_Mapping_Function)
  489.    is
  490.    begin
  491.       for J in Source'Range loop
  492.          Source (J) := Mapping.all (Source (J));
  493.       end loop;
  494.    end Translate;
  495.  
  496.    ----------
  497.    -- Trim --
  498.    ----------
  499.  
  500.    function Trim
  501.      (Source : in String;
  502.       Side   : in Trim_End)  --  ??? may need to change due to
  503.       return   String        --  ??? the new parameter Side
  504.    is
  505.       Low, High : Integer;
  506.  
  507.    begin
  508.       Low  := Index_Non_Blank (Source, Forward);
  509.  
  510.       --  All blanks case
  511.  
  512.       if Low = 0 then
  513.          return "";
  514.  
  515.       --  At least one non-blank
  516.  
  517.       else
  518.          High := Index_Non_Blank (Source, Backward);
  519.  
  520.          case Side is
  521.             when Strings.Left =>
  522.                declare
  523.                   Result : String (1 .. Source'Length - Low + 1);
  524.                begin
  525.                   Result := Source (Low .. Source'Length);
  526.                   return Result;
  527.                end;
  528.             when Strings.Right =>
  529.                declare
  530.                   Result : String (1 .. High);
  531.                begin
  532.                   Result := Source (1 .. High);
  533.                   return Result;
  534.                end;
  535.             when Strings.Both =>
  536.                declare
  537.                   Result : String (1 .. High - Low + 1);
  538.                begin
  539.                   Result := Source (Low .. High);
  540.                   return Result;
  541.                end;
  542.          end case;
  543.       end if;
  544.    end Trim;
  545.  
  546.    procedure Trim
  547.      (Source  : in out String;
  548.       Side    : in Trim_End;
  549.       Justify : in Alignment := Left;
  550.       Pad     : in Character := Space)
  551.    is
  552.    begin
  553.       Move (Trim (Source, Side),
  554.             Source,
  555.             Justify => Justify,
  556.             Pad => Space);
  557.    end Trim;
  558.  
  559.    function Trim
  560.      (Source : in String;
  561.       Left   : in Maps.Character_Set;
  562.       Right  : in Maps.Character_Set)
  563.       return   String
  564.    is
  565.       High, Low : Integer;
  566.  
  567.    begin
  568.       Low := Index (Source, Set => Left, Test  => Outside, Going => Forward);
  569.  
  570.       --  Case where source comprises only characters in Left
  571.  
  572.       if Low = 0 then
  573.          return "";
  574.       end if;
  575.  
  576.       High :=
  577.         Index (Source, Set => Right, Test  => Outside, Going => Backward);
  578.  
  579.       --  Case where source comprises only characters in Right
  580.  
  581.       if High = 0 then
  582.          return "";
  583.       end if;
  584.  
  585.       declare
  586.          Result : String (1 .. High - Low + 1);
  587.  
  588.       begin
  589.          Result := Source (Low .. High);
  590.          return Result;
  591.       end;
  592.    end Trim;
  593.  
  594.    procedure Trim
  595.      (Source  : in out String;
  596.       Left    : in Maps.Character_Set;
  597.       Right   : in Maps.Character_Set;
  598.       Justify : in Alignment := Strings.Left;
  599.       Pad     : in Character := Space)
  600.    is
  601.    begin
  602.       Move (Source  => Trim (Source, Left, Right),
  603.             Target  => Source,
  604.             Justify => Justify,
  605.             Pad     => Pad);
  606.    end Trim;
  607.  
  608. end Ada.Strings.Fixed;
  609.